﻿using System;
using System.Collections.Specialized;
using System.Configuration.Provider;
using System.Data;
using System.Web.Security;

namespace MembershipAdapter
{
    public class RoleProviderAdapter : RoleProvider
    {
        private IRoleRepository adaptee;
        private RoleProviderSettings settings;

        public IRoleRepository Adaptee
        {
            get
            {
                if (this.adaptee == null)
                {
                    throw new NoNullAllowedException("RoleProviderAdapter: adaptee property should be injected.");
                }

                return this.adaptee;
            }

            set { this.adaptee = value; }
        }

        public override string ApplicationName
        {
            get { return this.settings.AppName; }
            set { this.settings.AppName = value; }
        }

        public override void Initialize(string name, NameValueCollection config)
        {
            // NB: this method is internal!!! HttpRuntime.CheckAspNetHostingPermission(AspNetHostingPermissionLevel.Low, SR.Feature_not_supported_at_this_level);
            if (config == null)
            {
                throw new ArgumentNullException("config");
            }

            if (string.IsNullOrEmpty(name))
            {
                name = "RoleProviderAdapter";
            }

            if (string.IsNullOrEmpty(config["description"]))
            {
                config.Remove("description");
                config.Add("description", SR.GetString(SR.RoleProviderAdapter_description));
            }

            base.Initialize(name, config);
            var roleRepositoryType = string.Empty;
            SecUtility.GetAndRemoveStringAttribute(config, "roleRepositoryType", this.GetType().Name, ref roleRepositoryType);
            this.adaptee = this.InitializeAdaptee(roleRepositoryType, config);
        }

        public override void AddUsersToRoles(string[] usernames, string[] roleNames)
        {
            this.Adaptee.AddUsersToRoles(usernames, roleNames);
        }

        public override void CreateRole(string roleName)
        {
            this.Adaptee.CreateRole(roleName);
        }

        public override bool DeleteRole(string roleName, bool throwOnPopulatedRole)
        {
            var result = this.Adaptee.DeleteRole(roleName, throwOnPopulatedRole);
            return result;
        }

        public override string[] FindUsersInRole(string roleName, string usernameToMatch)
        {
            var result = this.Adaptee.FindUsersInRole(roleName, usernameToMatch);
            return result;
        }

        public override string[] GetAllRoles()
        {
            var result = this.Adaptee.GetAllRoles();
            return result;
        }

        public override string[] GetRolesForUser(string username)
        {
            var result = this.Adaptee.GetRolesForUser(username);
            return result;
        }

        public override string[] GetUsersInRole(string roleName)
        {
            var result = this.Adaptee.GetUsersInRole(roleName);
            return result;
        }

        public override bool IsUserInRole(string username, string roleName)
        {
            var result = this.Adaptee.IsUserInRole(username, roleName);
            return result;
        }

        public override void RemoveUsersFromRoles(string[] usernames, string[] roleNames)
        {
            this.Adaptee.RemoveUsersFromRoles(usernames, roleNames);
        }

        public override bool RoleExists(string roleName)
        {
            var result = this.Adaptee.RoleExists(roleName);
            return result;
        }

        private IRoleRepository InitializeAdaptee(string roleRepositoryType, NameValueCollection config)
        {
            if (string.IsNullOrWhiteSpace(roleRepositoryType))
            {
                throw new ProviderException(SR.GetString(SR.Missing_RoleRepository_type));
            }

            var type = Type.GetType(roleRepositoryType);
            var result = (IRoleRepository)Activator.CreateInstance(type, new object[] { config });
            this.settings = result.Settings;
            return result;
        }
    }
}